/**
 * File Average.java
 * ---------------------------------------------------------
 *
 * Copyright (C) 2012 David Bauske (david.bauske@googlemail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
 * following conditions:
 *
 * - The above copyright notice and this permission notice shall be included in all copies or substantial portions of
 * the Software.
 * - The origin of the software must not be misrepresented.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
 * FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * TL;DR: As long as you clearly give me credit for this software, you are free to use as you like, even in commercial
 * software, but don't blame me if it breaks something.
 */
package net.cl.util.math;

import java.util.ArrayList;
import java.util.List;

/**
 * Utility class for computing the average of a series of numbers.
 *
 * Credit for the original implementation goes to
 * <a href="http://www.javaspecialists.eu/archive/Issue124.html">Heinz Kabutz</a>.
 */
public class Average {

	private List<Double> values = new ArrayList<Double>();

	/**
	 * Add a new value to the series. Changes the values returned by mean() and
	 * {@link #standardDeviation()}.
	 *
	 * @param value The new value to add to the series.
	 */
	public void add(double value) {
		values.add(value);
	}

	/**
	 * Checks whether the add() method has been invoked yet.
	 *
	 * @return <i>true</i> if there is at least one element in the average series.
	 */
	public boolean hasElements() {
		return values.size() > 0;
	}

	/**
	 * Calculate and return the mean of the series of numbers. Throws an
	 * exception if this is called before the add() method.
	 *
	 * @return The mean of all the numbers added to the series.
	 * @throws IllegalStateException If no values have been added yet.
	 */
	public double mean() {
		int elements = values.size();
		if (elements == 0) {
			throw new IllegalStateException("No values in Average series.");
		}
		double sum = 0;
		for (double value : values) {
			sum += value;
		}
		return sum / elements;
	}

	/**
	 * Calculate and return the standard deviation of the series of numbers.
	 *
	 * @return the standard deviation of numbers added to the series.
	 * @throws IllegalStateException If no values have been added yet.
	 */
	public double standardDeviation() {
		double mean = mean();
		double stddevtotal = 0;
		for (double value : values) {
			double dev = value - mean;
			stddevtotal += dev * dev;
		}
		return Math.sqrt(stddevtotal / values.size());
	}
}